#include "tree.h"


cTreeTrunk::cTreeTrunk()
{
	D3DXMatrixIdentity(&m_matToWorld);
	D3DXMatrixIdentity(&m_matToParent);
	pFChildTrunk = NULL;
	pSChildTrunk = NULL;
	pParentTrunk = NULL;
}
void cTreeTrunk::Render(LPDIRECT3DDEVICE9 pDevice9,
						LPDIRECT3DVERTEXBUFFER9 pVB,
						LPDIRECT3DINDEXBUFFER9 pIB,
						ID3DXEffect* pEffect)
{
	cLight* pLight = GetLight();
	HR(pEffect->SetTechnique("TreeTech"));
	
	D3DXMATRIX matWorldInverTran;
	D3DXMatrixInverse( &matWorldInverTran, NULL, &m_matToWorld );
	D3DXMatrixTranspose( &matWorldInverTran, &matWorldInverTran );
	HR( pEffect->SetMatrix( "gWorldInverTran", &matWorldInverTran ) );
	HR( pEffect->SetMatrix( "gWorld", &m_matToWorld ) );
	HR( pEffect->SetMatrix( "gViewProj", &GetViewProj() ) );
	HR( pEffect->SetMatrix( "gWVP", &( m_matToWorld * GetViewProj() ) ) )
	HR( pEffect->SetValue( "gLightDir", &( pLight->GetDirection() ),sizeof( D3DVECTOR ) ) );

	UINT pass = 0;
	pEffect->Begin(&pass,0);
	pEffect->BeginPass(0);

	pEffect->CommitChanges();
	pDevice9->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,vertexOffset,TreeTrunkVertices,indexOffset,TreePrimCount);
	pEffect->EndPass();
	
	pEffect->End();
	if(pFChildTrunk && pSChildTrunk ){
		pFChildTrunk->Render(pDevice9,pVB,pIB,pEffect);
		pSChildTrunk->Render(pDevice9,pVB,pIB,pEffect);
	}
	return;
}

float cTreeTrunk::GetHeight()
{
	float fHeight = 0.0f;
	cTreeTrunk* pTrunk = pParentTrunk;
	while(pTrunk){
		fHeight+=pTrunk->m_fHeight;
		pTrunk = pTrunk->pParentTrunk;
	}
	return fHeight;
}
D3DXMATRIX cTreeTrunk::SetWorldMat()
{
	D3DXMATRIX mat;
	D3DXMatrixIdentity(&mat);
	cTreeTrunk* pTrunk = pParentTrunk;
	mat = m_matToParent*mat;
	while(pTrunk)
	{
		mat *= pTrunk->m_matToParent;
		pTrunk = pTrunk->pParentTrunk;
	}
	m_matToWorld = mat;
	return mat;
}

void cTreeTrunk::Release()
{
	if(pFChildTrunk&&pSChildTrunk){
		pFChildTrunk->Release();
		pSChildTrunk->Release();
	}
	else
	{
		pParentTrunk = NULL;
		delete pFChildTrunk;
		pFChildTrunk = NULL;
		delete pSChildTrunk;
		pSChildTrunk = NULL;
	}
}

//////////////////////////////////////////////////////////////////////////

void cTree::OnInit(float inHeight,float inRadius,D3DXVECTOR3 vec)
{
	m_pDevice9 = GetDevice9();
	m_pShaderMgr = GetShaderMgr();
	m_pTextureMgr = GetTextureMgr();
	
	HR(m_pDevice9->CreateVertexBuffer(sizeof(CommonVertex)*TrunkCount*TreeTrunkVertices,D3DUSAGE_WRITEONLY,
		SimpleFVF,D3DPOOL_MANAGED,&m_pVB,NULL));
	HR(m_pDevice9->CreateIndexBuffer(sizeof(DWORD)*TrunkCount*TreeTrunkIndices,D3DUSAGE_WRITEONLY,
		D3DFMT_INDEX32,D3DPOOL_MANAGED,&m_pIB,NULL));

	CreateTreeRoot(inHeight,inRadius,vec);
	CreateTree(m_pRootTrunk,inHeight*TreeHeightScale,inRadius*TreeRadiusScale,1);
	
}
void cTree::Render()
{
	ID3DXEffect* pEffect = m_pShaderMgr->GetShader("tree");

	HR(m_pDevice9->SetStreamSource(0,m_pVB,0,sizeof( CommonVertex ) ) );
	HR( m_pDevice9->SetIndices( m_pIB ) );
	HR( m_pDevice9->SetFVF( CommonFVF ) );

	pEffect->SetTexture("gTex0",m_pTextureMgr->GetTex("trunk"));
	
	m_pDevice9->BeginScene();
	m_pRootTrunk->Render(m_pDevice9,m_pVB,m_pIB,pEffect);
	m_pDevice9->EndScene();
}
void cTree::CreateTreeRoot(float inHeight,float inRadius,D3DXVECTOR3 vec)
{
	m_pRootTrunk = new cTreeTrunk;
	D3DXMatrixTranslation(&m_pRootTrunk->m_matToWorld,vec.x,vec.y,vec.z);
	m_pRootTrunk->m_matToParent = m_pRootTrunk->m_matToWorld;
	SetTreeTrunk(m_pRootTrunk,inHeight,inRadius);
}

void cTree::CreateTree(cTreeTrunk* pTrunk,float inHeight,float inRadius,int iTreeHeight)
{
	bool bTreeEnd = false;
	if(iTreeHeight >= TreeHeight)
		return;
	else if( iTreeHeight == TreeHeight - 1 )
		bTreeEnd = true;

	pTrunk->pFChildTrunk = new cTreeTrunk;
	pTrunk->pFChildTrunk->pParentTrunk = pTrunk;

	pTrunk->pSChildTrunk = new cTreeTrunk;
	pTrunk->pSChildTrunk->pParentTrunk = pTrunk;

	D3DXVECTOR3 rotateAxis = rand()%100*vZaxis + rand()%100*vXaxis;
	D3DXVec3Normalize( &rotateAxis, &rotateAxis );
	
	float fAngle = -D3DX_PI/6+D3DX_PI/3*rand()/RAND_MAX;
	float tempHeight = inHeight/2;
	tempHeight += rand()%int(inHeight/2);
	D3DXMATRIX matTranslate;
	D3DXMatrixTranslation(&matTranslate,0,pTrunk->m_fHeight,0);
	D3DXMatrixRotationAxis(&(pTrunk->pFChildTrunk->m_matToParent),&rotateAxis,fAngle-D3DX_PI/6);
	pTrunk->pFChildTrunk->m_matToParent *= matTranslate;
	SetTreeTrunk(pTrunk->pFChildTrunk, tempHeight, inRadius, bTreeEnd);
	pTrunk->pFChildTrunk->SetWorldMat();
	
	tempHeight = inHeight/2;
	tempHeight += rand()%int(inHeight/2);
	D3DXMatrixRotationAxis(&(pTrunk->pSChildTrunk->m_matToParent),&rotateAxis,fAngle+D3DX_PI/6);
	pTrunk->pSChildTrunk->m_matToParent *= matTranslate;
	SetTreeTrunk( pTrunk->pSChildTrunk, tempHeight, inRadius ,bTreeEnd );

	pTrunk->pSChildTrunk->SetWorldMat();

	CreateTree(pTrunk->pFChildTrunk,inHeight*TreeHeightScale,inRadius*TreeRadiusScale,iTreeHeight+1);
	CreateTree(pTrunk->pSChildTrunk,inHeight*TreeHeightScale,inRadius*TreeRadiusScale,iTreeHeight+1);
}

void cTree::SetTreeTrunk(cTreeTrunk* pTreeTrunk,float inHeight,float inRadius, bool treeEnd)
{
	pTreeTrunk->m_fHeight = inHeight;
	pTreeTrunk->m_fRadius = inRadius;
	pTreeTrunk->vertexOffset = vertexOffset;
	pTreeTrunk->indexOffset  = indexOffset;

	vector<D3DXVECTOR3> vecVertex;
	vector<DWORD> vecIndex;

	CreateTreeTrunk(vecVertex,vecIndex,inHeight,inRadius,treeEnd);
	CommonVertex* pVertex = NULL;
	HR(m_pVB->Lock(vertexOffset*sizeof( CommonVertex ),TreeTrunkVertices*sizeof( CommonVertex ),
		( void** )&pVertex,0 ) );
	for(int i = 0;i!=vecVertex.size();++i){
		pVertex[i].pos = vecVertex[i];
	}
	pVertex[ 0 ].normal = D3DXVECTOR3( 0, 1, 0 );
	pVertex[ 1 ].normal = D3DXVECTOR3( 0, 0, 0 );
	
	for( int i = 0; i != 2; ++i )
	{
		for( int j = 0; j != TreeCircleVerices; j += 2 )
		{
			int iIndex = 2 + j + i * TreeCircleVerices ;
			pVertex[ iIndex ].normal = pVertex[ iIndex ].pos - pVertex[ i ].pos;
			D3DXVec3Normalize( &pVertex[ iIndex ].normal, &pVertex[ iIndex ].normal );

			pVertex[ iIndex + 1 ].normal = pVertex[ iIndex ].pos - pVertex[ i ].pos;
			D3DXVec3Normalize( &pVertex[ iIndex + 1 ].normal, &pVertex[ iIndex + 1 ].normal );
			
		}
	}

	int iIndex = 2;
	float dTheta = 2*D3DX_PI /TreeBaseCircle;
	for( int i = 0; i != 2; ++i ){
		for( int j = 0; j != TreeCircleVerices; ++j)
		{
			pVertex[iIndex++].tex = D3DXVECTOR2((j*dTheta)/(2*D3DX_PI),i);
		}
	}

	HR(m_pVB->Unlock());

	DWORD* pIndex = NULL;
	HR(m_pIB->Lock(indexOffset*sizeof(DWORD),TreeTrunkIndices*sizeof(DWORD),(void**)&pIndex,0));
	for(int i = 0;i!=vecIndex.size();++i){
		pIndex[i] = vertexOffset + vecIndex[i];
	}
	HR(m_pIB->Unlock());

	vertexOffset += TreeTrunkVertices;
	indexOffset	 += TreeTrunkIndices;
}

void cTree::Release()
{
	m_pRootTrunk->Release();
	SAFE_DELETE(m_pRootTrunk);

	SAFE_RELEASE(m_pVB);
	SAFE_RELEASE(m_pIB);
}

//////////////////////////////////////////////////////////////////////////

void cTreeBuilder::OnInit(string treelocation,DWORD dwNum)
{
	ifstream fin;
	fin.open(treelocation,fstream::in);
	vector<D3DXVECTOR3> vecTreePos;
	float x,y,z;
	while(fin>>x>>y>>z)
	{
		vecTreePos.push_back(D3DXVECTOR3(x,y,z));
	}
	fin.close();
	RandomizePos(vecTreePos,dwNum);
	for(int i = 0;i!=dwNum;++i)
	{
		cTree* pTree = new cTree;
		pTree->OnInit(200,20,vecTreePos[i]);
		vecTree.push_back(pTree);
	}

	m_pShaderMgr = GetShaderMgr();
	m_pTextureMgr = GetTextureMgr();

	m_pShaderMgr->PushShader(L"../../files/fxFiles/tree.fx","tree");
	m_pTextureMgr->PushTex(L"../../files/textures/tree/trunk.jpg","trunk");
}

void cTreeBuilder::Render()
{
	for(int i = 0;i!=vecTree.size();++i)
	{
		vecTree[i]->Render();
	}
}
void cTreeBuilder::Update(float dt)
{
	return;
}
void cTreeBuilder::Release()
{
	for(int i = 0;i!=vecTree.size();++i)
	{
		vecTree[i]->Release();
		delete vecTree[i];
		vecTree[i] = NULL;
	}
	vecTree.clear();
}

//////////////////////////////////////////////////////////////////////////

void CreateTreeTrunk(vector<D3DXVECTOR3>& vecTree,vector<DWORD>& vecIndex,
	float inHeight,float inRadius, bool treeEnd)
{
	float dTheta = D3DX_PI*2/TreeBaseCircle; 
	float alpha = 0;
	D3DXVECTOR3 vCenter0 = D3DXVECTOR3(0.0f,inHeight,0.0f);
	D3DXVECTOR3 vCenter1 = D3DXVECTOR3(-0.0f,0.0f,0.0f);
	D3DXVECTOR3 vPoint[]={vCenter0 - inRadius*TreeRadiusScale*vZaxis,vCenter1 - inRadius*vZaxis};
	if( treeEnd ){
		vPoint[ 0 ] = vCenter0 - 1.0f*vZaxis;
	}
	vecTree.clear();
	vecIndex.clear();
	vecTree.resize(TreeTrunkVertices);
	vecIndex.resize(TreeTrunkIndices);
	int iIndex = 0;
	vecTree[iIndex++] = vCenter0; 
	vecTree[iIndex++] = vCenter1;
	for(int i = 0;i!=2;++i)
	{
		alpha = 0.0f;
		for(int j = 0;j<TreeCircleVerices;++j)
		{
			vecTree[iIndex].x = vPoint[i].x*cos(alpha) - vPoint[i].z*sin(alpha);
			vecTree[iIndex].z = vPoint[i].x*sin(alpha) + vPoint[i].z*cos(alpha);
			vecTree[iIndex].y = vPoint[i].y;
			++iIndex;
			alpha+=dTheta;
		}
	}
	iIndex = 0;
	for(int j = 0;j<TreeBaseCircle;++j)
	{
		vecIndex[iIndex++] = 1;
		vecIndex[iIndex++] = 2 + TreeCircleVerices + j;
		vecIndex[iIndex++] = 2 + TreeCircleVerices + j + 1;
	}
	for(int j = 0;j<TreeBaseCircle;++j)
	{
		vecIndex[iIndex++] = 0;
		vecIndex[iIndex++] = 2 + j + 1;
		vecIndex[iIndex++] = 2 + j ;
	}

	for(int i = 0;i<TreeBaseCircle;++i)
	{
		vecIndex[iIndex++] = 2 + i;
		vecIndex[iIndex++] = 2 + i + 1;
		vecIndex[iIndex++] = 2 + TreeCircleVerices + i;

		vecIndex[iIndex++] = 2 + TreeCircleVerices + i;
		vecIndex[iIndex++] = 2 + i + 1;
		vecIndex[iIndex++] = 2 + TreeCircleVerices + i + 1;
	}
}
